﻿ 
Imports System
Imports System.Drawing
Imports SlimDX
Imports SlimDX.Direct3D11
Imports SlimDX.Direct3D9


Namespace Engine

    Public Class Core3D

#Region "Members"
        'Private Window As New Surface
        Private dxInput As Input
        Public Width As Integer
        Public Height As Integer
        Public Handle As IntPtr
        Public Enabled As Boolean

        Friend D3DDevice As Direct3D9.Device

        Public matProj As Matrix
        Public matView As Matrix
        Private presentParams = New Direct3D9.PresentParameters

        Private deviceLost As Boolean
        Private _ElapsedGameTime As Long
        Private _frameRate, _frameCounter As Integer
        Private _StartTime As Long

        Public dxEntityManager As EntityManager
#End Region
#Region "Methods"
        Public Sub New(Window As Object, WinHandle As IntPtr, BasePath As String, Optional FullScreen As Boolean = False)

            BasePathResource = BasePath

            Try
                Dim d As SlimDX.Direct3D9.Direct3D = New Direct3D9.Direct3D


                Dim adapterInfo As AdapterInformation = d.Adapters(0) ' Helper class to gain access to information about the display adapter
                Dim caps As Capabilities = d.GetDeviceCaps(0, DeviceType.Hardware)


                ' Below are the required bare mininum, needed to initialize the D3D device.
                presentParams.BackBufferHeight = Window.Height          'BackBufferHeight, set to  the Window's height.
                presentParams.BackBufferWidth = Window.ClientRectangle.Width            ' BackBufferWidth, set to  the Window's width.
                presentParams.DeviceWindowHandle = WinHandle                       'DeviceWindowHandle, set to  the Window's handle.
                Handle = WinHandle



                presentParams.BackBufferCount = 1 'Number of backbuffers to create
                presentParams.BackBufferFormat = adapterInfo.CurrentDisplayMode.Format ' The current format of the display device

                presentParams.SwapEffect = SwapEffect.Discard ' How the backbuffer and the current display will be swapped
                presentParams.AutoDepthStencilFormat = Format.D24S8 ' 24 bits for the depth and 8 bits for the stencil
                presentParams.EnableAutoDepthStencil = True ' Let direct3d handle the depth buffers for the application
                presentParams.Windowed = True


                Try
                    D3DDevice = New Direct3D9.Device(d, 0, Direct3D9.DeviceType.Hardware, Window.Handle, Direct3D9.CreateFlags.HardwareVertexProcessing, presentParams)


                    ' build field of view
                    matProj = Matrix.PerspectiveFovLH((System.Math.PI / 4.0!), 1.0!, 1.0!, 5000.0!)
                    matView = Matrix.LookAtLH(New Vector3(450.0!, 350.0!, 750.0!), New Vector3(0.0!, 0.0!, 0.0!), New Vector3(0.0!, 1.0!, 0.0!))

                    D3DDevice.SetTransform(TransformState.Projection, matProj)

                    dxEntityManager = New EntityManager() ' Init objects managers

                    Enabled = True




                Catch ex As Direct3D9.Direct3D9Exception
                    Dispose()
                    Throw ex
                End Try

            Catch e As Exception
                Throw e
            End Try


            dxInput = New Input(Window.Handle, D3DDevice)


            'entityManager.Add(New Room(Window.D3DDevice))
            ' entityManager.Add(New SimpleTest(Window.D3DDevice))
            '  entityManager.Add(New Fountain(Window.D3DDevice))
            '  entityManager.Add(New Water(Window.D3DDevice))

            Dim ret As Result = D3DDevice.SetRenderState(RenderState.DiffuseMaterialSource, ColorSource.Color1)
            D3DDevice.SetRenderState(RenderState.SourceBlend, Blend.One)
            D3DDevice.SetRenderState(RenderState.BlendOperation, Blend.One)
        End Sub

        'Private Sub Update_FrameRate()


        '    Dim d As Long = DateTime.Now.Ticks
        '    Const ns As Long = 1000000 ' un secondo
        '    If ((d - _StartTime) > ns) Then
        '        _StartTime = d
        '        _frameRate = _frameCounter
        '        _frameCounter = 0
        '        RaiseEvent FrameRate(Me, New ScanEventArgs(_frameRate))
        '    End If
        '    _frameCounter += 1

        'End Sub

        Public Sub Add3DObject(e As Entity)
            e.Init(D3DDevice)
            dxEntityManager.Add(e)
        End Sub

        Public Sub Update()

            dxInput.UpdateCamera(D3DDevice)
            RaiseEvent MousePos(Me, New ScanEventArgs(dxInput.MousePos))

            dxEntityManager.Update(dxInput.matView, matProj)
            'Update_FrameRate()
        End Sub

        Public Sub Render()

            ' _ElapsedGameTime += (DateTime.Now.Millisecond - _ElapsedGameTime)
            BeginRender(Color.Black)
            RenderScene()
            FinishRender()
            _ElapsedGameTime += 1

        End Sub

        Public Sub FpsStart()
            _ElapsedGameTime = 0
        End Sub
        Function FpsGet() As Integer
            Dim d As Integer = _ElapsedGameTime
            _ElapsedGameTime = 0
            Return d
        End Function
        Private Sub Recover()

            Try

                D3DDevice.TestCooperativeLevel()

            Catch ex As Direct3D9.Direct3D9Exception

                Try

                    D3DDevice.Reset(presentParams)
                    deviceLost = False

                Catch ex2 As Direct3D9.Direct3D9Exception
                End Try

            End Try

        End Sub

        Public Sub RenderScene()
            dxEntityManager.Render(D3DDevice)
        End Sub
        Public Sub BeginRender(Color As System.Drawing.Color)

            If deviceLost Then
                Recover()
                If deviceLost Then Return
            End If

            If Not D3DDevice Is Nothing Then
                D3DDevice.Clear((ClearFlags.Target _
                    Or (ClearFlags.ZBuffer Or ClearFlags.Stencil)), Color, 1.0!, 0)
                D3DDevice.BeginScene()
            End If
        End Sub

        Public Sub FinishRender()

            If deviceLost Then Return
            D3DDevice.EndScene()
            Try
                D3DDevice.Present()
            Catch ex As Direct3D9.Direct3D9Exception
                deviceLost = True
            End Try

        End Sub

        Public Sub Dispose()
            If Not D3DDevice Is Nothing Then D3DDevice.Dispose()
            dxEntityManager.Dispose()
            ' GC.SuppressFinalize(Me)
        End Sub


        Public Class ScanEventArgs
            Inherits EventArgs
            Private _fps As TimeSpan
            Private _Action As String
            Private _args As Object


            Public Sub New(ByVal args As Object)
                _args = args
            End Sub
            Public ReadOnly Property args As Object
                Get
                    Return _args
                End Get
            End Property
            Public Sub New(ByVal action As String)
                _Action = action
            End Sub

            Public ReadOnly Property Action() As String
                Get
                    Return _Action
                End Get
            End Property

        End Class
#End Region
        Public Event MousePos As EventHandler(Of ScanEventArgs)
        Public Event FrameRate As EventHandler(Of ScanEventArgs)


    End Class


    'Class FPSCounter


    '    Private _game As Game
    '    Private _spriteBatch As SpriteBatch
    '    Private _font As SpriteFont
    '    Private _frameRate As Integer = 0
    '    Private _frameCounter As Integer = 0

    '    Private _elapsedTime As TimeSpan = TimeSpan.Zero

    '    Public Sub New(ByVal game As Game, ByVal spriteBatch As SpriteBatch)
    '        MyBase.New(game)
    '        _spriteBatch = spriteBatch
    '        _font = game.Content.Load("Fonts/Segoe UI Mono")
    '    End Sub

    '    Public Overrides Sub Update(ByVal gameTime As GameTime)
    '        _elapsedTime = (_elapsedTime + gameTime.ElapsedGameTime)
    '        If (_elapsedTime > TimeSpan.FromSeconds(1)) Then
    '            _elapsedTime = (_elapsedTime - TimeSpan.FromSeconds(1))
    '            _frameRate = _frameCounter
    '            _frameCounter = 0
    '        End If
    '        MyBase.Update(gameTime)
    '    End Sub

    '    Public Overrides Sub Draw(ByVal gameTime As GameTime)
    '        _frameCounter = (_frameCounter + 1)
    '        Dim fps As String = String.Format("FPS: {0}", _frameRate)
    '        _spriteBatch.Begin()
    '        _spriteBatch.DrawString(_font, fps, Vector2.Zero, Color.White)
    '        _spriteBatch.End()
    '        MyBase.Draw(gameTime)
    '    End Sub


    '    Dim Temp As Long
    '    ' Main loop

    'While Active
    '    Temp = GetTickCount
    '    ' Do game stuff here
    '    ' Calculate FPS
    '    If (StartTime < GetTickCount) Then
    '        FPS = FrameCount
    '    ' Code to show FPS goes here
    '        FrameCount = 0
    '        StartTime = (GetTickCount + 1000)
    '    End If
    '    FrameCount = (FrameCount + 1)
    '    DoEvents

    'End While

    'End Class

End Namespace